<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MyBatis 日志格式化工具</title>
    <style>
        :root {
            --bg-color: #f5f7fa;
            --panel-bg: #ffffff;
            --border-color: #d1d9e6;
            --header-bg: #4a5568; /* 蓝灰色 */
            --header-text: #ffffff;
            --btn-primary-bg: #4299e1; /* 柔和蓝色 */
            --btn-primary-hover: #3182ce;
            --btn-secondary-bg: #a0aec0; /* 柔和灰色 */
            --btn-secondary-hover: #718096;
            --text-color: #2d3748;
            --success-bg: #c6f6d5;
            --success-text: #22543d;
            --error-bg: #fed7d7;
            --error-text: #742a2a;
            --code-bg: #f7fafc;
            --font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
        }

        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            font-family: var(--font-family);
            background-color: var(--bg-color);
            color: var(--text-color);
            height: 100vh;
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }

        .header {
            background-color: var(--header-bg);
            color: var(--header-text);
            padding: 15px 20px;
            text-align: center;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            flex-shrink: 0;
        }

        .header h1 {
            margin: 0;
            font-size: 1.5rem;
            font-weight: 500;
        }

        .container {
            display: flex;
            flex: 1;
            padding: 20px;
            gap: 20px;
            overflow: hidden;
        }

        @media (max-width: 768px) {
            .container {
                flex-direction: column;
            }
        }

        .panel {
            background-color: var(--panel-bg);
            border: 1px solid var(--border-color);
            border-radius: 4px;
            display: flex;
            flex-direction: column;
            overflow: hidden;
            flex: 1;
            min-width: 0;
        }

        .panel-header {
            padding: 12px 15px;
            background-color: var(--header-bg);
            color: var(--header-text);
            font-weight: 500;
            font-size: 1rem;
        }

        .panel-content {
            flex: 1;
            padding: 15px;
            overflow: auto;
        }

        textarea {
            width: 100%;
            height: 100%;
            padding: 10px;
            border: 1px solid var(--border-color);
            border-radius: 4px;
            font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
            font-size: 14px;
            resize: none;
            background-color: var(--code-bg);
        }

        textarea:focus {
            outline: 1px solid var(--btn-primary-bg);
        }

        #output-container {
            height: 100%;
            border: 1px solid var(--border-color);
            border-radius: 4px;
            padding: 10px;
            background-color: var(--code-bg);
            overflow: auto;
            font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
            white-space: pre-wrap;
            word-break: break-all;
            font-size: 14px;
        }

        .button-group {
            display: flex;
            gap: 10px;
            padding: 15px;
            background-color: var(--bg-color);
            border-top: 1px solid var(--border-color);
            flex-wrap: wrap;
        }

        button {
            padding: 8px 15px;
            background-color: var(--btn-secondary-bg);
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-weight: 500;
            transition: background-color 0.2s ease;
            flex: 1;
            min-width: 100px;
            font-size: 0.9rem;
        }

        button:hover {
            background-color: var(--btn-secondary-hover);
        }

        .btn-primary {
            background-color: var(--btn-primary-bg);
        }

        .btn-primary:hover {
            background-color: var(--btn-primary-hover);
        }

        .status {
            margin: 10px 15px 0 15px;
            padding: 10px 15px;
            border-radius: 4px;
            text-align: center;
            font-weight: 500;
            transition: opacity 0.3s ease;
        }

        .status.success {
            background-color: var(--success-bg);
            color: var(--success-text);
        }

        .status.error {
            background-color: var(--error-bg);
            color: var(--error-text);
        }

        .hidden {
            display: none;
        }
    </style>
</head>
<body>

<div class="header">
    <h1>MyBatis 日志格式化工具</h1>
</div>

<div class="container">
    <div class="panel">
        <div class="panel-header">
            MyBatis 日志输入
        </div>
        <div class="panel-content">
            <textarea id="log-input" placeholder='在此粘贴您的 MyBatis 日志...'>DEBUG [main] - ==>  Preparing: SELECT * FROM users WHERE id = ? AND name = ? AND age > ?
DEBUG [main] - ==> Parameters: 123(Long), Alice(String), 18(Integer)
</textarea>
        </div>
        <div class="button-group">
            <button id="format-btn" class="btn-primary">格式化 SQL</button>
            <button id="copy-input-btn">复制输入</button>
            <button id="clear-input-btn">清空输入</button>
        </div>
        <div id="input-status" class="status hidden"></div>
    </div>

    <div class="panel">
        <div class="panel-header">
            格式化后的 SQL
        </div>
        <div class="panel-content">
            <div id="output-container">-- 等待格式化结果 --</div>
        </div>
        <div class="button-group">
            <button id="copy-output-btn">复制 SQL</button>
            <button id="clear-output-btn">清空输出</button>
        </div>
        <div id="output-status" class="status hidden"></div>
    </div>
</div>

<script>
    // DOM 元素
    const logInput = document.getElementById('log-input');
    const outputContainer = document.getElementById('output-container');
    const formatBtn = document.getElementById('format-btn');
    const copyInputBtn = document.getElementById('copy-input-btn');
    const clearInputBtn = document.getElementById('clear-input-btn');
    const copyOutputBtn = document.getElementById('copy-output-btn');
    const clearOutputBtn = document.getElementById('clear-output-btn');
    const inputStatus = document.getElementById('input-status');
    const outputStatus = document.getElementById('output-status');

    // 显示状态消息
    function showStatus(element, message, isSuccess) {
        element.textContent = message;
        element.className = `status ${isSuccess ? 'success' : 'error'}`;
        element.classList.remove('hidden');
        setTimeout(() => {
            element.classList.add('hidden');
        }, 3000);
    }

    // 格式化 MyBatis 日志
    function formatMyBatisLog() {
        const logText = logInput.value.trim();
        if (!logText) {
            showStatus(inputStatus, '输入不能为空', false);
            outputContainer.textContent = '-- 请输入 MyBatis 日志 --';
            return;
        }

        try {
            const lines = logText.split('\n');
            let preparingLine = '';
            let parametersLine = '';

            // 查找包含 Preparing 和 Parameters 的行
            for (const line of lines) {
                if (line.includes('Preparing:')) {
                    preparingLine = line.split('Preparing:')[1].trim();
                } else if (line.includes('Parameters:')) {
                    parametersLine = line.split('Parameters:')[1].trim();
                }
            }

            if (!preparingLine) {
                throw new Error('未找到 "Preparing:" 行');
            }

            let formattedSQL = preparingLine;
            
            if (parametersLine) {
                // 解析参数
                const params = [];
                // 匹配参数，例如: 123(Long), Alice(String), null
                const paramRegex = /([^,]+?)\(([^,)]+?)\)(?:,|$)/g;
                let match;
                while ((match = paramRegex.exec(parametersLine)) !== null) {
                    let value = match[1].trim();
                    const type = match[2].trim();

                    // 根据类型处理参数值
                    if (type === 'String' || type === 'Date') {
                        // 字符串和日期需要加引号
                        value = `'${value.replace(/'/g, "''")}'`; // 转义单引号
                    } else if (value.toLowerCase() === 'null') {
                        // null 值保持不变
                        value = 'NULL';
                    }
                    // 数字类型(Number, Integer, Long, Double, Float, BigDecimal等)直接使用
                    // Boolean 类型也直接使用
                    params.push(value);
                }

                // 替换 SQL 中的 ? 占位符
                let paramIndex = 0;
                formattedSQL = formattedSQL.replace(/\?/g, () => {
                    if (paramIndex < params.length) {
                        return params[paramIndex++];
                    }
                    return '?'; // 如果参数不足，保留 ?
                });
            }

            outputContainer.textContent = formattedSQL;
            showStatus(inputStatus, 'MyBatis 日志格式化成功', true);
        } catch (e) {
            console.error("格式化错误:", e);
            showStatus(inputStatus, `格式化失败: ${e.message}`, false);
            outputContainer.textContent = `-- 错误: ${e.message} --`;
        }
    }

    // 复制文本到剪贴板
    async function copyToClipboard(text, button, successMessage = "已复制!") {
        if (!text) return;
        try {
            await navigator.clipboard.writeText(text);
            const originalText = button.textContent;
            button.textContent = successMessage;
            setTimeout(() => { button.textContent = originalText; }, 2000);
        } catch (err) {
            console.error('复制失败: ', err);
            showStatus(button.id.includes('input') ? inputStatus : outputStatus, '复制失败: ' + err.message, false);
        }
    }

    // 事件监听
    formatBtn.addEventListener('click', formatMyBatisLog);
    copyInputBtn.addEventListener('click', () => {
        copyToClipboard(logInput.value, copyInputBtn, "已复制!");
    });
    clearInputBtn.addEventListener('click', () => {
        logInput.value = '';
        showStatus(inputStatus, '输入已清空', true);
    });
    
    copyOutputBtn.addEventListener('click', () => {
        copyToClipboard(outputContainer.textContent, copyOutputBtn, "已复制!");
    });
    clearOutputBtn.addEventListener('click', () => {
        outputContainer.textContent = '-- 等待格式化结果 --';
        showStatus(outputStatus, '输出已清空', true);
    });

    // 页面加载完成后初始化
    window.addEventListener('load', formatMyBatisLog);

</script>

</body>
</html>
